package com.flyiu.data.consistency.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.flyiu.data.consistency.context.DistributedTransactionContext;
import com.flyiu.data.consistency.context.DistributedTransactionScheduledQueue;
import com.flyiu.data.consistency.model.DistributedTransactionInstance;
import com.flyiu.data.consistency.model.DistributedTransactionPartner;
import com.flyiu.data.consistency.model.DistributedTransactionState;
import com.flyiu.data.consistency.repository.DistributedTransactionInstanceRepository;

/**
 * 
 * <p>分布式事务管理服务
 * </p>
 *
 * @author chenjh@flyiu.com
 * @version $Id: DistributeServiceImpl.java, v 0.1 2018年8月2日 下午2:37:46 chenjh Exp $
 */
@Service
@Transactional()
public class DistributeServiceImpl implements DistributeService {

	@Autowired
	private DistributedTransactionInstanceRepository instanceRepository;
	@Autowired
	private PartnerService partnerService;

	/* (non-Javadoc)
	 * @see com.flyiu.data.consistency.service.DistributeService#start(java.lang.String, java.lang.String)
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void start(String name, String businessId) {
		DistributedTransactionInstance instance = new DistributedTransactionInstance();
		instance.setName(name);
		instance.setBusinessId(businessId);
		instance.setTransactionState(DistributedTransactionState.INIT);
		DistributedTransactionContext.setInstance(instance);
		instanceRepository.save(instance);
	}

	public void updateState(DistributedTransactionState state) {
		DistributedTransactionInstance instance = DistributedTransactionContext.getInstance();
		instance.setTransactionState(state);
		instanceRepository.save(instance);
		
		if(state==DistributedTransactionState.CANCEL || state== DistributedTransactionState.COMMIT){
			DistributedTransactionContext.clear();
		}
		
	}

	/* (non-Javadoc)
	 * @see com.flyiu.data.consistency.service.DistributeService#preCommit()
	 */
	@Override
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void preCommit() {
		updateState(DistributedTransactionState.PRE_COMMIT);
	}

	/* (non-Javadoc)
	 * @see com.flyiu.data.consistency.service.DistributeService#commit()
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void commit() {
		DistributedTransactionInstance instance = DistributedTransactionContext.getInstance();
		List<DistributedTransactionPartner> partners = instance.getPartners();
		partners.stream().filter(partner -> partner.getTransactionState() != DistributedTransactionState.COMMIT)
				.forEach(partnerService::commit);
		DistributedTransactionScheduledQueue.add(instance);
//		updateState(DistributedTransactionState.COMMIT);
	}

	/* (non-Javadoc)
	 * @see com.flyiu.data.consistency.service.DistributeService#preRollback()
	 */
	@Override
	public void preRollback() {
		updateState(DistributedTransactionState.PRE_CANCEL);
	}

	/* (non-Javadoc)
	 * @see com.flyiu.data.consistency.service.DistributeService#rollback()
	 */
	@Override
	public void rollback() {
		DistributedTransactionInstance instance = DistributedTransactionContext.getInstance();
		List<DistributedTransactionPartner> partners = instance.getPartners();
		partners.stream().filter(partner -> partner.getTransactionState() == DistributedTransactionState.INIT)
				.forEach(partnerService::rollback);
		updateState(DistributedTransactionState.CANCEL);
	}


}
